/****************************************************************************
**
** This file is part of the KD Chart library.
**
** SPDX-FileCopyrightText: 2001-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
**
** SPDX-License-Identifier: MIT
**
****************************************************************************/

#ifndef KDCHARTMEASURE_H
#define KDCHARTMEASURE_H

#include "KDChartEnums.h"
#include "KDChartGlobal.h"
#include <QDebug>
#include <QStack>
#include <Qt>

/** \file KDChartMeasure.h
 *  \brief Declaring the class KDChart::Measure.
 *
 *
 */

QT_BEGIN_NAMESPACE
class QObject;
class QPaintDevice;
QT_END_NAMESPACE

namespace KDChart {

/**
 * \class Measure KDChartMeasure.h KDChartMeasure
 * \brief Measure is used to specify relative and absolute sizes in KDChart, e.g. font sizes.
 *
 */

class KDCHART_EXPORT Measure
{
public:
    Measure();
    /*implicit*/ Measure(qreal value,
                         KDChartEnums::MeasureCalculationMode mode = KDChartEnums::MeasureCalculationModeAuto,
                         KDChartEnums::MeasureOrientation orientation = KDChartEnums::MeasureOrientationAuto);
    Measure(const Measure &);
    Measure &operator=(const Measure &);

    void setValue(qreal val)
    {
        mValue = val;
    }
    qreal value() const
    {
        return mValue;
    }

    void setCalculationMode(KDChartEnums::MeasureCalculationMode mode)
    {
        mMode = mode;
    }
    KDChartEnums::MeasureCalculationMode calculationMode() const
    {
        return mMode;
    }

    /**
     * The reference area must either be derived from AbstractArea
     * or from QWidget, so it can also be derived from AbstractAreaWidget.
     */
    void setRelativeMode(const QObject *area,
                         KDChartEnums::MeasureOrientation orientation)
    {
        mMode = KDChartEnums::MeasureCalculationModeRelative;
        mArea = area;
        mOrientation = orientation;
    }

    /**
     * \brief This is a convenience method for specifying a value,
     *  implicitly setting the calculation mode to MeasureCalculationModeAbsolute.
     *
     * Calling setAbsoluteValue( value ) is the same as calling
\verbatim
    setValue( value );
    setCalculationMode( KDChartEnums::MeasureCalculationModeAbsolute );
\endverbatim
     */
    void setAbsoluteValue(qreal val)
    {
        mMode = KDChartEnums::MeasureCalculationModeAbsolute;
        mValue = val;
    }

    /**
     * The reference area must either be derived from AbstractArea
     * or from QWidget, so it can also be derived from AbstractAreaWidget.
     */
    void setReferenceArea(const QObject *area)
    {
        mArea = area;
    }
    /**
     * The returned reference area will be derived from AbstractArea
     * or QWidget or both.
     */
    const QObject *referenceArea() const
    {
        return mArea;
    }

    void setReferenceOrientation(KDChartEnums::MeasureOrientation orientation)
    {
        mOrientation = orientation;
    }
    KDChartEnums::MeasureOrientation referenceOrientation() const
    {
        return mOrientation;
    }

    /**
     * The reference area must either be derived from AbstractArea
     * or from QWidget, so it can also be derived from AbstractAreaWidget.
     */
    qreal calculatedValue(const QObject *autoArea, KDChartEnums::MeasureOrientation autoOrientation) const;
    qreal calculatedValue(const QSizeF &autoSize, KDChartEnums::MeasureOrientation autoOrientation) const;
    const QSizeF sizeOfArea(const QObject *area) const;

    bool operator==(const Measure &) const;
    bool operator!=(const Measure &other) const
    {
        return !operator==(other);
    }

private:
    qreal mValue = 0.0;
    KDChartEnums::MeasureCalculationMode mMode = KDChartEnums::MeasureCalculationModeAuto;
    const QObject *mArea = nullptr;
    KDChartEnums::MeasureOrientation mOrientation = KDChartEnums::MeasureOrientationAuto;
}; // End of class Measure

/**
 * Auxiliary class used by the KDChart::Measure and KDChart::Chart class.
 *
 * Normally there should be no need to call any of these methods yourself.
 *
 * They are used by KDChart::Chart::paint( QPainter*, const QRect& )
 * to adjust all of the relative Measures according to the target
 * rectangle's size.
 *
 * Default factors are (1.0, 1.0)
 */
class GlobalMeasureScaling
{
public:
    static GlobalMeasureScaling *instance();

    GlobalMeasureScaling();
    virtual ~GlobalMeasureScaling();

public:
    /**
     * Set new factors to be used by all Measure objects from now on.
     * Previous values will be saved on a stack internally.
     */
    static void setFactors(qreal factorX, qreal factorY);

    /**
     * Restore factors to the values before the previous call to
     * setFactors. The current values are popped off a stack internally.
     */
    static void resetFactors();

    /**
     * Return the currently active factors.
     */
    static const QPair<qreal, qreal> currentFactors();

    /**
     * Set the paint device to use for calculating font metrics.
     */
    static void setPaintDevice(QPaintDevice *paintDevice);

    /**
     * Return the paint device to use for calculating font metrics.
     */
    static QPaintDevice *paintDevice();

private:
    QStack<QPair<qreal, qreal>> mFactors;
    QPaintDevice *m_paintDevice = nullptr;
};
}

#if !defined(QT_NO_DEBUG_STREAM)
KDCHART_EXPORT QDebug operator<<(QDebug, const KDChart::Measure &);
#endif /* QT_NO_DEBUG_STREAM */

#endif // KDCHARTMEASURE_H
